#include"EPollPoller.h"
#include"Logger.h"
#include"Channel.h"
#include<unistd.h>
#include<string.h>
#include <errno.h>
//#include<errno.h>
//表示channel是否添加到poller，与channel的成员index_相关，它的初始值就是-1，表示还没有添加到里面
//用来区分，如果再次添加channel时候发现是kAdded表示已经添加到里面了，那这次操作就是更新channel中的事件
const int kNew=-1;//一个channel还没有添加到poller里边
const int kAdded=1;//一个channel已经添加到poller里面吗
const int kDeleted=2;//删除

EPollPoller::EPollPoller(Eventloop *loop)
    :Poller(loop)
    ,epollfd_(::epoll_create1(EPOLL_CLOEXEC))
    ,events_(kInitEventListSize)
{
    if(epollfd_<0)
    {
        LOG_FATAL("epoll_create error:%d \n",errno);
    }
}
EPollPoller::~EPollPoller()
{
    ::close(epollfd_);
}
//返回具体发生事件的时间点，主要调用的是epoll_wait
Timestamp EPollPoller::poll(int timeoutMs,ChannelList *activeChannels)
{
    //poll这里短时间是接受大量的高并发请求的，如果在这里使用LOG_INFO则每次调用都会影响它的性能
    //实际上这里应该用LOG_DEBUG,只要我们不定义debug，他就不用调用进而不会影响它的性能
    LOG_INFO("func=%s => fd total count:%lu \n",__FUNCTION__,Channels_.size());

    //第二个参数是存放发生事件的数组地址，但是为了方便扩容，
    //我们用的是vector.events_.size()返回的是size_t类型，但是这里参数要求int，所以使用转换
    int numEvents=::epoll_wait(epollfd_,&*events_.begin(),static_cast<int>(events_.size()),timeoutMs);

    int saveErrno=errno;
    Timestamp now(Timestamp::now());
    if(numEvents>0)
    {
        LOG_INFO("%d events happend \n",numEvents);
        fillActiveChannels(numEvents,activeChannels);
        //扩容
        if(numEvents==events_.size())
        {
            events_.resize(events_.size()*2);
        }
    }
    else if (numEvents==0)
    {
        LOG_DEBUG("%s timeout! \n",__FUNCTION__);
    }
    else//外部中断，还要接着执行业务逻辑
    {
        if(saveErrno != EINTR)
        {
            errno=saveErrno;//虽然日志不需要了，但有些设计会保留 errno 给上层处理。
            LOG_ERROR("EPollPoller::poll() err!");
        }
    }
    return now;
}
void EPollPoller::updateChannel(Channel *channel) 
{
    const int index=channel->index();////获取状态，是未注册到Poller、已注册还是已删除
    LOG_INFO("func=%s => fd=%d events=%d index=%d \n",__FUNCTION__,channel->fd(),channel->events(),index);
    if(index==kNew || index==kDeleted)
    {
        if(index==kNew)
        {
            int fd=channel->fd();
            Channels_[fd]=channel;
        }
        
        channel->set_index(kAdded);
        update(EPOLL_CTL_ADD,channel);
    }
    else//此时channel已经在poller上注册过了
    {
        int fd=channel->fd();
        if(channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL,channel);
            channel->set_index(kDeleted);
        }
        else
        {
            update(EPOLL_CTL_MOD,channel);
        }
    }
}
//从poller中删除channel
void EPollPoller::removeChannel(Channel *channel) 
{
    
    int fd=channel->fd();
    Channels_.erase(fd);
    LOG_INFO("func=%s => fd=%d\n",__FUNCTION__,fd);
    int index=channel->index();
    if(index==kAdded)
    {
        update(EPOLL_CTL_DEL,channel);
    }
    channel->set_index(kNew);
}

//填写活跃的连接
void EPollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels) const
{
    for(int i=0;i< numEvents;++i)
    {
        Channel* channel=static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel);//Eventloop就拿到了poller给它返回的所有发生事件的channel列表了
    }
}
//更新channel通道,做的是事件的增删改
void EPollPoller::update(int operation ,Channel* channel)
{
    epoll_event event;
    bzero(&event, sizeof event);
    int fd=channel->fd();

    event.events=channel->events();
    event.data.fd=fd;
    event.data.ptr=channel;

    if(::epoll_ctl(epollfd_,operation,fd,&event)<0)
    {
        if(operation==EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error:%d\n",errno);
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error%d \n",errno);
        }
    }
}